package org.kingtop.action;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.serializer.SerializeFilter;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.cache.CacheException;
import org.kingtop.cache.app.UserCacheUtil;
import org.kingtop.lang.BaseException;
import org.kingtop.model.IUserPO;
import org.kingtop.service.ILogBaseService;
import org.kingtop.util.FileUtil;
import org.kingtop.util.WebRequestUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ModelAttribute;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * 基础action类，主要用于定义一些通用方法，包括用于返回json的方法和记录日志的方法
 *
 * @author 陈金波
 * @date 2017年12月24日 下午3:10:49
 * @Copyright: 2017 chen jinbo. All rights reserved.
 */
public class BaseAction {

	public final Logger log = LoggerFactory.getLogger(getClass());

	/**
	 * 默认的时间格式化方式，为yyyy-MM-dd HH:mm:ss
	 */
	public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";

	/**
	 * 默认路径
	 */
	public static String basePath = null;
	
	static {
		initBasePath();
	}

	/**
	 * 初始化basePath的值
	 * @author 陈金波  
	 * @date   2018年1月25日 下午9:02:52  
	 * @return void
	 */
	private static void initBasePath() {
		if(basePath == null) {
			try {
				basePath = FileUtil.getProperty("application.properties", "basePath");
				if(basePath == null) {
					basePath = "";
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	private ILogBaseService logBaseService;

	@Autowired(required = false)
	public void setLogBaseService(ILogBaseService logBaseService) {
		this.logBaseService = logBaseService;
	}
	
	/**
	 * 为每个页面返回basePath，还可以用于解决使用NGINX做代理时候的问题
	 * @author 陈金波  
	 * @date   2018年1月25日 下午9:07:40  
	 * @param request
	 * @return String
	 */
	@ModelAttribute(name="basePath")
	public String getBasePath(HttpServletRequest request) {
		if(StringUtils.isNotBlank(basePath)) {
			return basePath;
		}
		String path = request.getContextPath();
		basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
		return basePath;
	}

	/**
	 * 将一个对象转换成字符串<br>
	 * 过滤字段用法如下：<br>
	 *  TargetStrategy targetStrategy2 = new TargetStrategy(ResultBean.class);
	 *  targetStrategy2.setFields(new String[]{"statusCode"});
	 * 
	 * @param statusCode
	 *            状态码 {@link StatusCodeEnum}
	 * @param object
	 *            转换的对象
	 * @param message
	 *            要传递的消息
	 * @param filters 过滤字段设置
	 * @param dateFormat
	 *            时间格式化 例：yyyy-MM-dd HH:mm:ss
	 * @param features
	 *            其他格式设置
	 * @return json json结果
	 */
	protected <T> String getJson(int statusCode, T object, String message, SerializeFilter[] filters, String dateFormat, SerializerFeature... features) {
		ResultBean<T> result = new ResultBean<T>(statusCode, object, message);
		return JSON.toJSONString(result, SerializeConfig.globalInstance, filters, dateFormat, JSON.DEFAULT_GENERATE_FEATURE, features);
	}

	/**
	 * @param statusCode
	 *            状态码 {@link StatusCodeEnum}
	 * @param object
	 *            转换的对象
	 * @param message
	 *            要传递的消息
	 * @param filters
	 *            过滤字段设置
	 * @return json
	 */
	protected <T> String getJson(int statusCode, T object, String message, SerializeFilter... filters) {
		return this.getJson(statusCode, object, message, filters, DEFAULT_DATE_TIME_FORMAT);
	}

	/**
	 * @param object
	 *            转换的对象
	 * @param message
	 *            要传递的消息
	 * @param filters
	 *            过滤字段设置
	 * @return json
	 */
	protected <T> String getJson(T object, String message, SerializeFilter... filters) {
		return this.getJson(StatusCodeEnum.OK.getCode(), object, message, filters);
	}

	/**
	 * @param object
	 *            转换的对象
	 * @param filters
	 *            过滤字段设置
	 * @return json
	 */
	protected <T> String getJson(T object, SerializeFilter... filters) {
		return this.getJson(object, StatusCodeEnum.OK.getMessage(), filters);
	}

	/**
	 * @param message
	 *            要传递的消息
	 * @param filters
	 *            过滤字段设置
	 * @return json
	 */
	protected String getJson(String message, SerializeFilter... filters) {
		return this.getJson("", message, filters);
	}

	/**
	 * @param codeEnum
	 *            状态码 {@link StatusCodeEnum}
	 * @param object
	 *            转换的对象
	 * @param message
	 *            要传递的消息
	 * @param filters
	 *            过滤字段设置
	 * @return json
	 */
	protected <T> String getJson(StatusCodeEnum codeEnum, T object, String message, SerializeFilter... filters) {
		return this.getJson(codeEnum.getCode(), object, message, filters);
	}

	/**
	 * @param codeEnum
	 *            状态码 {@link StatusCodeEnum}
	 * @param object
	 *            转换的对象
	 * @param filters
	 *            过滤字段设置
	 * @return json
	 */
	protected <T> String getJson(StatusCodeEnum codeEnum, T object, SerializeFilter... filters) {
		return this.getJson(codeEnum.getCode(), object, codeEnum.getMessage(), filters);
	}

	/**
	 * @param codeEnum
	 *            状态码 {@link StatusCodeEnum}
	 * @param filters
	 *            过滤字段设置
	 * @return json
	 */
	protected String getJson(StatusCodeEnum codeEnum, SerializeFilter... filters) {
		return this.getJson(codeEnum.getCode(), null, codeEnum.getMessage(), filters);
	}

	/**
	 * 添加日志
	 * 
	 * @param moduleType
	 *            日志类型
	 * @param content
	 *            内容
	 * @param userMessage
	 *            用户消息，给给用查看的消息
	 */
	protected void addLog(String moduleType, String content, String userMessage) {
		try {
			IUserPO user = UserCacheUtil.get(SecurityUtils.getSubject().getPrincipal().toString());
			StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
			StackTraceElement methodElement = (StackTraceElement) stackTrace[2];
			// 方法名称
			String methodName = methodElement.getMethodName();
			String className = this.getClass().getName();
			String ip = WebRequestUtil.getRemoteIp();
			if (this.logBaseService != null) {
				this.logBaseService.addLog(user != null ? user.getId() : -1L, moduleType, content, userMessage, ip,
						className, methodName);
			}
		} catch (CacheException e) {
			e.printStackTrace();
			throw new BaseException(e, log);
		}
	}

}
